<?php


namespace EchoPHP\Foundation\Console;

use EchoPHP\Console\Command;
use EchoPHP\Foundation\Application;
use EchoPHP\Foundation\Exception\Handler as ExceptionHandler;
use Exception;
use ReflectionClass;
use EchoPHP\Console\Application as CommandApplication;

class Kernel {
    /**
     * 应用程序实例
     * @var \EchoPHP\Foundation\Application
     */
    protected $app;

    /**
     * 应用程序执行的中间件
     * @var array
     */
    protected $middleware = [];

    protected $commandApp;

    /**
     * 应用程序启动执行类
     * @var array
     */
    protected $bootstrappers = [
        \EchoPHP\Foundation\BootStrap\LoadAppEnvironment::class,
        \EchoPHP\Foundation\BootStrap\LoadConfiguration::class,
        \EchoPHP\Foundation\BootStrap\HandleException::class,
        \EchoPHP\Foundation\BootStrap\HandleSession::class,
        \EchoPHP\Foundation\BootStrap\RegisterFacades::class,
        \EchoPHP\Foundation\BootStrap\RegisterProviders::class,
        \EchoPHP\Foundation\BootStrap\BootProviders::class,
    ];

    /**
     * 实例化内核程序
     * @param Application $app
     */
    public function __construct(Application $app) {
        $this->app = $app;
    }


    /**
     * console控制台程序处理逻辑
     * @param \Symfony\Component\Console\Input\InputInterface $input
     * @param \Symfony\Component\Console\Output\OutputInterface $output
     * @return int
     */
    public function handle($input, $output = null) {

        try {
            $this->bootstrap();

            $command = $input->getFirstArgument();
            $this->registerCommand($command);

            $this->getCommandApplication()->addDefaultOptions();

            return $this->getCommandApplication()->run($input, $output);
        } catch (Exception $e) {
            $this->reportException($e);

            $this->renderException($output, $e);

            return 1;
        }
    }

    /**
     * 获取命令行执行应用程序实例
     * @return CommandApplication
     */
    protected function getCommandApplication() {
        if (!$this->commandApp) {
            $this->commandApp = new CommandApplication($this->app, $this->app->getVersion());
        }

        return $this->commandApp;
    }

    /**
     * 注册控制台命令
     * @param $command
     * @return string
     * @throws \ReflectionException
     */
    protected function registerCommand($command) {
        $commandItems = explode(':', $command);
        $commandClass = 'App\\Command\\';
        while (count($commandItems) > 1) {
            $commandClass .= ucfirst(array_shift($commandItems)) . '\\';
        }
        $commandClass .= ucfirst(array_shift($commandItems));

        if (is_subclass_of($commandClass, Command::class) && !(new ReflectionClass($commandClass))->isAbstract()) {
            return $this->getCommandApplication()->resolve($commandClass);
        }
        throw new \InvalidArgumentException('控制台程序[' . $command . ']未定义');
    }

    /**
     * 初始化应用程序
     * @throws Exception
     */
    protected function bootstrap() {
        if (!$this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers);
        }
    }

    /**
     * 报告异常信息
     * @param Exception $e
     */
    protected function reportException(Exception $e) {
        $this->app[ExceptionHandler::class]->report($e);
    }

    /**
     * 渲染输出异常信息
     * @param $request
     * @param Exception $e
     * @return
     */
    protected function renderException($request, Exception $e) {
        return $this->app[ExceptionHandler::class]->renderForConsole($request, $e);
    }


}